package com.luobr.backend.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luobr.backend.common.ResponseCode;
import com.luobr.backend.constant.ImageConstant;
import com.luobr.backend.constant.UserConstant;
import com.luobr.backend.exception.BusinessException;
import com.luobr.backend.exception.ThrowUtils;
import com.luobr.backend.mapper.SpaceMapper;
import com.luobr.backend.model.dto.analyze.*;
import com.luobr.backend.model.entity.Image;
import com.luobr.backend.model.entity.Space;
import com.luobr.backend.model.vo.analyze.*;
import com.luobr.backend.model.vo.user.UserLoginVO;
import com.luobr.backend.service.ImageService;
import com.luobr.backend.service.SpaceAnalyzeService;
import com.luobr.backend.service.SpaceService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 罗念笙
 * @createDate 2025-03-11 14:55:44
 */
@Service
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceAnalyzeService {

    @Resource
    private SpaceService spaceService;
    @Resource
    private ImageService imageService;

    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, UserLoginVO loginVO) {
        // 校验权限
        checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest,loginVO);
        boolean queryPublic = spaceUsageAnalyzeRequest.isQueryPublic();
        boolean queryAll = spaceUsageAnalyzeRequest.isQueryAll();
        if(queryPublic || queryAll) {
            QueryWrapper<Image> imageQueryWrapper = new QueryWrapper<>();
            imageQueryWrapper.select("imgSize");
            if(queryPublic) {
                // 查询公开图片，需要查询 spaceId 为 null 的数据
                imageQueryWrapper.isNull("spaceId");
            }
            List<Object> imageList = imageService.getBaseMapper().selectObjs(imageQueryWrapper);
            long usedSize = imageList.stream().mapToLong(result -> result instanceof Long ? (Long) result : 0).sum();
            long imgCount  = imageList.size();
            // 封装返回结果
            return new SpaceUsageAnalyzeResponse(usedSize,null,null,imgCount,null,null);
        } else {
            // 查询个人空间
            Space space = spaceService.getById(spaceUsageAnalyzeRequest.getSpaceId());
            Long totalSize = space.getTotalSize();
            Long maxSize = space.getMaxSize();
            // 后端直接算好百分比，这样前端可以直接展示
            double sizeUsageRatio = NumberUtil.round(totalSize * 100.0 / maxSize, 2).doubleValue();
            Long totalCount = space.getTotalCount();
            Long maxCount = space.getMaxCount();
            double countUsageRatio = NumberUtil.round(totalCount * 100.0 / maxCount, 2).doubleValue();
            // 封装返回结果
            return new SpaceUsageAnalyzeResponse(totalSize, maxSize,sizeUsageRatio,totalCount,maxCount,countUsageRatio);
        }
    }

    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest, UserLoginVO loginVO) {
        // 校验权限
        checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequest,loginVO);
        // 查询条件
        QueryWrapper<Image> imageWrapper = new QueryWrapper<>();
        // 查询字段以及分组
        imageWrapper.select("category","COUNT(*) AS count","SUM(imgSize) AS totalSize").groupBy("category");
        // 填充分许请求参数
        fillAnalyzeQueryWrapper(spaceCategoryAnalyzeRequest,imageWrapper);
        // 返回参数
        return imageService.getBaseMapper().selectMaps(imageWrapper).stream().map(item -> {
            String category = item.getOrDefault("category", "未分类").toString();
            long count = ((Number) item.get("count")).longValue();
            long totalSize = ((Number) item.get("totalSize")).longValue();
            return new SpaceCategoryAnalyzeResponse(category,count,totalSize);
        }).collect(Collectors.toList());
    }

    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, UserLoginVO loginVO) {
        // 校验权限
        checkSpaceAnalyzeAuth(spaceTagAnalyzeRequest,loginVO);
        // 查询条件
        QueryWrapper<Image> imageWrapper = new QueryWrapper<>();
        // 填充分许请求参数
        fillAnalyzeQueryWrapper(spaceTagAnalyzeRequest,imageWrapper);
        // 查询字段以及分组
        imageWrapper.select("tags");
        // 查询出所有标签的 Json 格式的字符串列表
        List<String> tagJsonList = imageService.getBaseMapper().selectObjs(imageWrapper).
                stream().filter(ObjUtil::isNotNull).map(Object::toString).collect(Collectors.toList());
        // 将每个 Json 格式字符串标签转换成字符列表，然后统计并映射成 标签 对应 标签次数
        Map<String, Long> tagMapCount = tagJsonList.stream().flatMap(tagsJson -> JSONUtil.toList(tagsJson, String.class).stream()).
                collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
        // 最后返回 响应包装类
        return tagMapCount.entrySet().stream().sorted((v1,v2) -> Long.compare(v1.getValue(),v2.getValue())). // 降序排序
                map(item -> new SpaceTagAnalyzeResponse(item.getKey(),item.getValue())).collect(Collectors.toList());
    }

    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, UserLoginVO loginVO) {
        // 校验权限
        checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequest,loginVO);
        // 查询条件
        QueryWrapper<Image> imageWrapper = new QueryWrapper<>();
        // 填充分许请求参数
        fillAnalyzeQueryWrapper(spaceSizeAnalyzeRequest,imageWrapper);
        // 查询字段以及分组
        imageWrapper.select("imgSize");
        // 查询并转换图片大小类型列表
        List<Long> sizeList = imageService.getBaseMapper().selectObjs(imageWrapper).stream().
                map(size -> ((Number) size).longValue()).collect(Collectors.toList());
        // 定义有序列表，存储不同大小区间映射图片数量
        Map<String,Long> sizeRangeMap = new LinkedHashMap<>();
        sizeRangeMap.put("<100KB",sizeList.stream().filter(size -> size < ImageConstant.IMAGE_SIZE_RANGE.SMALL).count());
        sizeRangeMap.put("100KB-500KB",sizeList.stream().filter(size -> size < ImageConstant.IMAGE_SIZE_RANGE.MEDIUM && size > ImageConstant.IMAGE_SIZE_RANGE.SMALL).count());
        sizeRangeMap.put("500KB-1MB",sizeList.stream().filter(size -> size < ImageConstant.IMAGE_SIZE_RANGE.LARGE && size > ImageConstant.IMAGE_SIZE_RANGE.MEDIUM).count());
        sizeRangeMap.put(">1MB",sizeList.stream().filter(size -> size > ImageConstant.IMAGE_SIZE_RANGE.LARGE).count());
        // 返回封装类
        return sizeRangeMap.entrySet().stream().map(item -> new SpaceSizeAnalyzeResponse(item.getKey(), item.getValue())).
                collect(Collectors.toList());
    }

    @Override
    public List<SpaceUserActionAnalyzeResponse> getSpaceUserActionAnalyze(SpaceUserActionAnalyzeRequest spaceUserActionAnalyzeRequest, UserLoginVO loginVO) {
        // 校验权限
        checkSpaceAnalyzeAuth(spaceUserActionAnalyzeRequest,loginVO);
        // 查询条件
        QueryWrapper<Image> imageWrapper = new QueryWrapper<>();
        // 填充分许请求参数
        fillAnalyzeQueryWrapper(spaceUserActionAnalyzeRequest,imageWrapper);
        // 管理员可以分析其他用户的行为
        Long userId = spaceUserActionAnalyzeRequest.getUserId();
        imageWrapper.eq(ObjUtil.isNotNull(userId),"userId",userId);
        // 判断用户请求的时间类型
        String timeDimension = spaceUserActionAnalyzeRequest.getTimeDimension();
        switch (timeDimension) {
            case "day":   imageWrapper.select("DATE_FORMAT(createTime,'%Y-%m-%d') AS period","count(*) AS count");
                          break;
            case "week":  imageWrapper.select("YEARWEEK(createTime) AS period","count(*) AS count");
                          break;
            case "month": imageWrapper.select("DATE_FORMAT(createTime,'%Y-%m') AS period","count(*) AS count");
                          break;
            default:
                throw new BusinessException(ResponseCode.PARAMS_ERROR,"请求的时间范围不存在");
        }
        imageWrapper.groupBy("period").orderByAsc("period");
        // 图片上传时间映射对应时间的图片数量
        List<Map<String, Object>> periodMapCopuntList = imageService.getBaseMapper().selectMaps(imageWrapper);
        // 返回结果
        return periodMapCopuntList.stream().map(item -> {
                    String period = item.get("period").toString();
                    long count = ((Number) item.get("count")).longValue();
                    return new SpaceUserActionAnalyzeResponse(period,count);
                }).collect(Collectors.toList());
    }

    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest) {
        // 构造查询条件
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        // 添加查询条件以及排序
        queryWrapper.select("id", "spaceName", "userId", "totalSize")
                .orderByDesc("totalSize")
                .last("LIMIT " + spaceRankAnalyzeRequest.getTopN()); // 取前 N 名
        // 查询结果
        return spaceService.list(queryWrapper);
    }

    private static void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest, QueryWrapper<Image> queryWrapper) {
        if (spaceAnalyzeRequest.isQueryAll()) {
            return;
        }
        if (spaceAnalyzeRequest.isQueryPublic()) {
            queryWrapper.isNull("spaceId");
            return;
        }
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        if (spaceId != null) {
            queryWrapper.eq("spaceId", spaceId);
            return;
        }
        throw new BusinessException(ResponseCode.PARAMS_ERROR, "未指定查询范围");
    }

    private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest, UserLoginVO loginUser) {
        // 校验参数
        ThrowUtils.throwIf(spaceAnalyzeRequest == null, ResponseCode.PARAMS_ERROR);
        // 检查权限
        if (spaceAnalyzeRequest.isQueryAll() || spaceAnalyzeRequest.isQueryPublic()) {
            // 全空间分析或者公共图库权限校验：仅管理员可访问
            ThrowUtils.throwIf(!UserConstant.USER_ROLE.ADMIN.equals(loginUser.getUserRole()), ResponseCode.NO_AUTH_ERROR, "无权访问公共图库");
        } else {
            // 私有空间权限校验
            Long spaceId = spaceAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ResponseCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ResponseCode.NOT_FOUND_ERROR, "空间不存在");
            // 私有空间，仅本人空间可操作
            ThrowUtils.throwIf(!space.getUserId().equals(loginUser.getId()), ResponseCode.NO_AUTH_ERROR);
        }
    }
}